SELECTOR_KERNEL_CS  equ 8 ; 内核代码段的选择符，用于远跳转指令
                             ; 其描述符是GDT的第2项

; 导入函数
extern  cstart
extern  exception_handler

; 导入全局变量
extern  gdt_ptr
extern  idt_ptr
extern  disp_pos    ; 用于显示字符串的当前位置

[SECTION .bss]
StackSpace      resb    2 * 1024
StackTop:       ; 栈顶

[section .text]     ; 代码在此

global  _start  ; 导出 _start

; 导出异常处理函数名（在protect.c中使用）：
global  divide_error
global  single_step_exception
global  nmi
global  breakpoint_exception
global  overflow
global  bounds_check
global  inval_opcode
global  copr_not_available
global  double_fault
global  copr_seg_overrun
global  inval_tss
global  segment_not_present
global  stack_exception
global  general_protection
global  page_fault
global  copr_error

_start:

    ; 把 esp 从 LOADER 挪到 KERNEL
    mov esp, StackTop   ; 堆栈在 bss 段中

    mov dword [disp_pos], 0

    sgdt    [gdt_ptr]   ; cstart() 中将会用到 gdt_ptr
    call    cstart  ; 在此函数中改变了gdt_ptr，让它指向新的GDT
                ; 增加了初始化IDTR指针结构idt_ptr的代码
    lgdt    [gdt_ptr]   ; 使用新的GDT

    lidt    [idt_ptr]

    jmp SELECTOR_KERNEL_CS:csinit
csinit:         ; 这个跳转指令强制使用刚刚初始化的结构

    ud2         ; 用于产生#UD异常（6号：未定义的无效操作）的CPU指令
    ;jmp 0x40:0 ; 用于产生#GP异常（13号：常规保护错误）

    ;push   0
    ;popfd  ; Pop top of stack into EFLAGS

    hlt

; 中断和异常 -- 异常
divide_error:
    push 0xFFFFFFFF ; no err code
    push 0      ; vector_no = 0
    jmp exception
single_step_exception:
    push 0xFFFFFFFF ; no err code
    push 1      ; vector_no = 1
    jmp exception
nmi:
    push 0xFFFFFFFF ; no err code
    push 2      ; vector_no = 2
    jmp exception
breakpoint_exception:
    push 0xFFFFFFFF ; no err code
    push 3      ; vector_no = 3
    jmp exception
overflow:
    push 0xFFFFFFFF ; no err code
    push 4      ; vector_no = 4
    jmp exception
bounds_check:
    push 0xFFFFFFFF ; no err code
    push 5      ; vector_no = 5
    jmp exception
inval_opcode:
    push 0xFFFFFFFF ; no err code
    push 6      ; vector_no = 6
    jmp exception
copr_not_available:
    push 0xFFFFFFFF ; no err code
    push 7      ; vector_no = 7
    jmp exception
double_fault:
    push 8      ; vector_no = 8
    jmp exception
copr_seg_overrun:
    push 0xFFFFFFFF ; no err code
    push 9      ; vector_no = 9
    jmp exception
inval_tss:
    push 10     ; vector_no = A
    jmp exception
segment_not_present:
    push 11     ; vector_no = B
    jmp exception
stack_exception:
    push 12     ; vector_no = C
    jmp exception
general_protection:
    push 13     ; vector_no = D
    jmp exception
page_fault:
    push 14     ; vector_no = E
    jmp exception
copr_error:
    push 0xFFFFFFFF ; no err code
    push 16     ; vector_no = 10h
    jmp exception

exception:
    call    exception_handler
    add esp, 4*2    ; 让栈顶指向 EIP，堆栈中从顶向下依次是：EIP、CS、EFLAGS
    hlt
